// // 2.导入模块
// let obj=require("./one");//用一个变量接受模块导出的数据
// console.log(obj);//{ a: 123, b: 456, c: { name: 'qwe', age: 19 } }

// 完成的操作：
// （1）main.js里面的obj变量等于exports对象
// (2)也就是require通过各种查找，最终找到了exports这个对象
// （3）并且将exports这个对象赋值给了obj变量
// （4）obj变量就是exports对象

// =>本质就是引用赋值，require和exports指向的是同一个对象

// 证明是引用赋值：
// let obj=require("./one");
// console.log(obj);
// setTimeout(function(){
//     console.log(obj);
// },4000);

// 一、module.exports和exports的关系
// 1.commonJS中是没有module.exports的概念的，但是为了实现模块的导出，
// node中使用的是Module的类，每一个模块都是Module的一个实例，也就是module
// 所以在node中真正用于导出的根本不是exports，而是module.exports
// 因此module才是导出的真正实现者

// 2.为什么使用exports也可以导出呢?
// 这是因为module对象的exports属性是exports对象的一个引用
// 也就是说：module.exports=exports=main.js中的obj变量

// 总结：commonJS的导入：require
//      commonJS的导入：module.exports

// 二、require工作步骤
// require是一个函数，可以帮助我们引入一个文件（模块）中导出的对象
// 语法：let 变量=require("x")

// 情况一：X是一个node的核心模块名称，比如path,http
// 举例：require("path"):核心模块，直接返回模块，并且停止查找

// 情况二：X是一个node的一个普通模块名称，比如readline-sync,mysql
// 举例：require("readline-sync"):会在项目中找到node_modules文件夹，在文件夹中查找该模块

// 情况三：X是以/或者./或者../开头
// 第一步：将X当做一个文件在对应的目录下查找
// 1.如果有后缀，按照后缀的格式查找对应的文件
// 2.如果没有后缀，会按照如下顺序查找：
//   （1）直接找文件X
//   （2）查找X.js文件
//   （3）查找X.json文件
//   （4）查找X.node文件

// 举例：
// let one=require("./one");
// console.log(one);

// 第二步：如果没有找到对应的文件，会将X作为目录，查找目录下的index文件
// （1）查找index.js
// （2）查找index.json
// （3）查找index.node

// 如果再找不到就报错
// 举例：
// let person=require("./test");
// console.log(person);//{ name: '小米', age: 19 }

// 三、模块的加载过程
// 1.模块在被第一次引入的时候，模块中的js文件会被运行一次
// 2.如果多次引入，会缓存，最终只运行一次
// 因为每一个模块对象module里面都有一个属性loaded,
// 该属性取值为false表示还没有加载（运行），为true表示已经加载了

// let person1=require("./test");
// let person2=require("./test");
// let person3=require("./test");
// console.log(person1,person2,person3);

// 3.如果有循环引入，加载顺序按照深度优先算法进行

// 四、commonJS规范的缺点
// 1.commonJS加载模块的同步的
// 同步意味着只有等到对应的模块加载完毕，当前模块中的内容才能被运行
// 这个在服务器上不会有问题，因为服务器加载的js都是本地文件，加载速度非常快
// 但是如果是在浏览器中，就会有问题
// 因为浏览器加载js文件都需要先从服务器上将js文件下载下来，之后在加载运行，
// 采用同步就意味着后续的js代码都无法正常运行，即使是一些简单的DOM操作

// 2.因此在浏览器中，通常不使用commonJS规范
// 注意：webpack中使用commonJS不会有问题，因为webpack会把commonJS转成浏览器可以直接执行的代码

// 3.在早期，为了适合浏览器，会使用CMD或者AMD模块化规范，但是现在已经不用这两个了
// 现在主要使用ES module模块化规范

// 五、ES module（ES6的模块化实现）
// 1.ES module和commonJS的不同：
//   ES module：导出使用export,导入使用import
//   commonJS:导出module.exports,导入使用require
//   ES module采用编译器的静态分析，并且也加入了动态引用的方法
// 2.注意：采用ES module将自动采用严格模式："use strict"

// import {a,b,c} from "./one.js";//注意：文件名后面一定要加后缀
// console.log(a,b,c);

// 六、ES module模块化规范——export导出的多种写法
// 1.在语句声明前直接加上export
// 举例：export let a=123;

// 2.将所有需要导出的变量，都放在export后面的{}中
// 注意：这里的{}不是对象的意思，表示列表，把需要导出的数据依次填入其中

// 3.导出是给变量起一个别名,通过as关键字
// import {a1,b1,c1} from "./one.js";//注意：文件名后面一定要加后缀
// console.log(a1,b1,c1);

// 七、ES module模块化规范——import导出的多种写法
// 1.import {变量列表} from "模块"
// 注意：这里的{}不是对象，表示一个列表，里面存放所有导出的变量
//      括号里面变量名必须和导出的变量名相同，顺序可以不同,
//      也可以选择填入需要的变量名，不一定完全导入
//      同时，引入的变量是只读的，不能修改
// import {a,c} from "./one.js";//注意：文件名后面一定要加后缀
// console.log(a,c);

// 2.导入的时候给变量取别名，通过as关键字
// import {a as a1,b as b2} from "./one.js";
// console.log(a1,b2);

// 3.导入的时候使用*，将所有的变量放入一个对象中,
// 为了方便使用该对象，使用as给*取一个别名
// import * as obj from "./one.js";
// console.log(obj.default());

// 八、默认导出（default）
// 1.之前学习的都是有名字的导出，导出的数据都有名字：
// 导出时export指定了名字
// 导入时import需要知道具体的名字
// 2.没有名字的导出，叫默认导出
// 默认导出export可以不需要指定名字
// 在导入时也不需要使用{}，并且可以自己取名字
// 它也方便了我们和现有的commonJS等规范相互操作

// 3.注意：每一个模块中，默认导出只能有一个；默认导出可以和普通导出一起使用

// 4.导入接受默认导出的数据，使用如下的语句：
// import myname from "./one.js";//该语句只能导入默认导出的数据
// console.log(myname);//直接就是默认导出的数据
// myname就是自定义的变量名，用于接受默认导出的数据

// 下面语句，可以同时导入默认导出和普通导出的数据（即所有数据）
// import * as obj from "./one.js";
// console.log(obj);

// 九、import函数
//1.注意： import关键字用于导入数据，但是不可以放到其他逻辑代码中，会发生语法错误
// let z=10;
// if(z>5){
//     import * as obj from "./one.js";
// }

// 因为ES module在被JS引擎解析时，就必须知道它的依赖关系，
// 由于在这个时候js代码没有任何运行，所以无法在进行类似if判断中判断代码的执行情况，
// 甚至拼接路径的写法也是错误的，因为必须到运行的时候才能确定path的值

// 2.但是在某些情况下，确实需要动态来加载某一个模块
// 如果根据不同的条件，动态来选择加载模块的路径
// 这个时候可以使用import函数
// import函数的返回值是一个promise对象，可以通过then方法获取结果

// let z=10;
// if(z<5){
//     import("./one.js").then(function(res){
//         console.log(res);
//     })
// }

// 十、ES module的解析过程
// ES module的解析过程可以划分为三个阶段：
// 1.构建阶段：根据地址查找js文件，并且下载，将其解析成模块记录
// 2.实例化阶段：对模块记录进行实例化，并且分配内存空间，解析模块的导入和导出语句，将模块指向对应的内存地址
// 3.运行阶段：运行代码，计算值，并且将值填充到内存地址中


// 总结：
// 实现模块化开发的主要规范：
// 一、commonJS规范：module.exports导出数据；require导入数据
// 二、ES Module规范：export导出数据，import导入数据
// 